﻿using ICSharpCode.WinFormsUI.Controls;
using ICSharpCode.WinFormsUI.Controls.NodeControls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DevelopAssistant.GuiTest
{
    public partial class Form13 : Form
    {
        public Form13()
        {
            InitializeComponent();
        }

        private void Form13_Load(object sender, EventArgs e)
        {            
            LoadTreeGrid();
        }

        private void LoadTreeGrid()
        {
            NTreeViewColumn treeViewColumn = new NTreeViewColumn();
            treeViewColumn.Header = "Name";
            //treeViewColumn.SortOrder = System.Windows.Forms.SortOrder.None;
            //treeViewColumn.TooltipText = "File name";
            treeViewColumn.Width = 250;
            treeView1.Columns.Add(treeViewColumn);

            treeViewColumn = new NTreeViewColumn();
            treeViewColumn.Header = "Size";
            //treeViewColumn.SortOrder = System.Windows.Forms.SortOrder.None;
            //treeViewColumn.TooltipText = "File name";
            treeViewColumn.Width = 200;
            treeView1.Columns.Add(treeViewColumn);

            treeViewColumn = new NTreeViewColumn();
            treeViewColumn.Header = "Date";
            //treeViewColumn.SortOrder = System.Windows.Forms.SortOrder.None;
            //treeViewColumn.TooltipText = "File name";
            treeViewColumn.Width = 200;
            treeView1.Columns.Add(treeViewColumn);

            NodeStateIcon nodeStateIcon = new NodeStateIcon();
            nodeStateIcon.DataPropertyName = "Icon";
            treeView1.NodeControls.Add(nodeStateIcon);

            NodeCheckBox nodeCheck = new NodeCheckBox();
            nodeCheck.DataPropertyName = "IsChecked";
            treeView1.NodeControls.Add(nodeCheck);

            NodeTextBox nodeTextBox1 = new NodeTextBox();
            nodeTextBox1.DataPropertyName = "Name";
            treeView1.NodeControls.Add(nodeTextBox1);

            NodeTextBox nodeTextBox2 = new NodeTextBox();
            nodeTextBox2.Column = 1;
            nodeTextBox2.DataPropertyName = "Size";
            treeView1.NodeControls.Add(nodeTextBox2);

            NodeTextBox nodeTextBox3 = new NodeTextBox();
            nodeTextBox3.Column = 2;
            nodeTextBox3.DataPropertyName = "Date";           
            treeView1.NodeControls.Add(nodeTextBox3);

            treeView1.UseColumns = true;

            treeView1.Model = new SortedNTreeViewModel(new FolderBrowserModel());
        }
    }

    public abstract class BaseItem
    {
        private string _path = "";
        public string ItemPath
        {
            get { return _path; }
            set { _path = value; }
        }

        private Image _icon;
        public Image Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }

        private long _size = 0;
        public long Size
        {
            get { return _size; }
            set { _size = value; }
        }

        private DateTime _date;
        public DateTime Date
        {
            get { return _date; }
            set { _date = value; }
        }

        public abstract string Name
        {
            get;
            set;
        }

        private BaseItem _parent;
        public BaseItem Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }

        private bool _isChecked;
        public bool IsChecked
        {
            get { return _isChecked; }
            set
            {
                _isChecked = value;
                //if (Owner != null)
                //    Owner.OnNodesChanged(this);
            }
        }

        private FolderBrowserModel _owner;
        public FolderBrowserModel Owner
        {
            get { return _owner; }
            set { _owner = value; }
        }

        /*public override bool Equals(object obj)
		{
			if (obj is BaseItem)
				return _path.Equals((obj as BaseItem).ItemPath);
			else
				return base.Equals(obj);
		}

		public override int GetHashCode()
		{
			return _path.GetHashCode();
		}*/

        public override string ToString()
        {
            return _path;
        }
    }

    public class RootItem : BaseItem
    {
        public RootItem(string name, FolderBrowserModel owner)
        {
            ItemPath = name;
            Owner = owner;
        }

        public override string Name
        {
            get
            {
                return ItemPath;
            }
            set
            {
            }
        }
    }

    public class FolderItem : BaseItem
    {
        public override string Name
        {
            get
            {
                return Path.GetFileName(ItemPath);
            }
            set
            {
                string dir = Path.GetDirectoryName(ItemPath);
                string destination = Path.Combine(dir, value);
                Directory.Move(ItemPath, destination);
                ItemPath = destination;
            }
        }

        public FolderItem(string name, BaseItem parent, FolderBrowserModel owner)
        {
            ItemPath = name;
            Parent = parent;
            Owner = owner;
        }
    }

    public class FileItem : BaseItem
    {
        public override string Name
        {
            get
            {
                return Path.GetFileName(ItemPath);
            }
            set
            {
                string dir = Path.GetDirectoryName(ItemPath);
                string destination = Path.Combine(dir, value);
                File.Move(ItemPath, destination);
                ItemPath = destination;
            }
        }

        public FileItem(string name, BaseItem parent, FolderBrowserModel owner)
        {
            ItemPath = name;
            Parent = parent;
            Owner = owner;
        }
    }

    public class FolderBrowserModel : INTreeViewModel
    {
        private BackgroundWorker _worker;
        private List<BaseItem> _itemsToRead;
        private Dictionary<string, List<BaseItem>> _cache = new Dictionary<string, List<BaseItem>>();

        public FolderBrowserModel()
        {
            _itemsToRead = new List<BaseItem>();

            _worker = new BackgroundWorker();
            _worker.WorkerReportsProgress = true;
            _worker.DoWork += new DoWorkEventHandler(ReadFilesProperties);
            _worker.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
        }

        void ReadFilesProperties(object sender, DoWorkEventArgs e)
        {
            while (_itemsToRead.Count > 0)
            {
                BaseItem item = _itemsToRead[0];
                _itemsToRead.RemoveAt(0);

                System.Threading.Thread.Sleep(50); //emulate time consuming operation
                if (item is FolderItem)
                {
                    DirectoryInfo info = new DirectoryInfo(item.ItemPath);
                    item.Date = info.CreationTime;
                }
                else if (item is FileItem)
                {
                    FileInfo info = new FileInfo(item.ItemPath);
                    item.Size = info.Length;
                    item.Date = info.CreationTime;
                    if (info.Extension.ToLower() == ".ico")
                    {
                        Icon icon = new Icon(item.ItemPath);
                        item.Icon = icon.ToBitmap();
                    }
                    else if (info.Extension.ToLower() == ".bmp")
                    {
                        item.Icon = new Bitmap(item.ItemPath);
                    }
                }
                _worker.ReportProgress(0, item);
            }
        }

        void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            OnNodesChanged(e.UserState as BaseItem);
        }

        private NTreeViewPath GetPath(BaseItem item)
        {
            if (item == null)
                return NTreeViewPath.Empty;
            else
            {
                Stack<object> stack = new Stack<object>();
                while (item != null)
                {
                    stack.Push(item);
                    item = item.Parent;
                }
                return new NTreeViewPath(stack.ToArray());
            }
        }

        public System.Collections.IEnumerable GetChildren(NTreeViewPath treePath)
        {
            List<BaseItem> items = null;
            if (treePath.IsEmpty())
            {
                if (_cache.ContainsKey("ROOT"))
                    items = _cache["ROOT"];
                else
                {
                    items = new List<BaseItem>();
                    _cache.Add("ROOT", items);
                    //foreach (string str in Environment.GetLogicalDrives())
                    //    items.Add(new RootItem(str, this));
                    items.Add(new RootItem("D:\\开发工具", this));
                }
            }
            else
            {
                BaseItem parent = treePath.LastNode as BaseItem;
                                
                if (parent != null)
                {
                    if (_cache.ContainsKey(parent.ItemPath))
                        items = _cache[parent.ItemPath];
                    else
                    {
                        items = new List<BaseItem>();
                        try
                        {
                            if(!parent.ItemPath.Contains("$RECYCLE.BIN")&&
                                !parent.ItemPath.Contains("$Recycle.Bin")&&
                                !parent.ItemPath.Contains("Documents and Settings") && 
                                !parent.ItemPath.Contains("System Volume Information"))
                            {
                                foreach (string str in Directory.GetDirectories(parent.ItemPath))
                                    items.Add(new FolderItem(str, parent, this));
                                foreach (string str in Directory.GetFiles(parent.ItemPath))
                                {
                                    FileItem item = new FileItem(str, parent, this);
                                    items.Add(item);
                                }
                            }                            
                        }
                        catch (IOException)
                        {
                            return null;
                        }
                        _cache.Add(parent.ItemPath, items);
                        _itemsToRead.AddRange(items);
                        if (!_worker.IsBusy)
                            _worker.RunWorkerAsync();
                    }
                }
            }
            return items;
        }

        public bool IsLeaf(NTreeViewPath treePath)
        {
            return treePath.LastNode is FileItem;
        }

        public event EventHandler<NTreeViewModelEventArgs> NodesChanged;
        internal void OnNodesChanged(BaseItem item)
        {
            if (NodesChanged != null)
            {
                NTreeViewPath path = GetPath(item.Parent);
                NodesChanged(this, new NTreeViewModelEventArgs(path, new object[] { item }));
            }
        }

        public event EventHandler<NTreeViewModelEventArgs> NodesInserted;
        public event EventHandler<NTreeViewModelEventArgs> NodesRemoved;
        public event EventHandler<NTreeViewPathEventArgs> StructureChanged;
        public void OnStructureChanged()
        {
            if (StructureChanged != null)
                StructureChanged(this, new NTreeViewPathEventArgs());
        }
    }
}
